﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace WeManageService
{
    public delegate void RefreshData();

	public class PlanQueryArgs
	{
		public int QueryTimeType { get; set; }  //-1: 不查询此项 0: 查询开始时间, 1: 查询结束时间
		public DateTime MinTime { get; set; }   //最早时间
		public DateTime MaxTime { get; set; }   //最晚时间
		public string RegexString { get; set; } //正则表达式 空字符串: 不查询此项
		public int PState { get; set; }         //任务状态 -1: 不查询此项

		public PlanQueryArgs()
		{
			QueryTimeType = -1;
			MinTime = new DateTime();
			MaxTime = new DateTime();
			RegexString = "";
			PState = -1;
		}

		public PlanQueryArgs(int qtType, DateTime minT, DateTime maxT, string regex, int ps)
		{
			QueryTimeType = qtType;
			MinTime = minT;
			MaxTime = maxT;
			RegexString = regex;
			PState = ps;
		}

		public static long PosMod(long a, long b) => (a % b + b) % b;

		public bool JudgePlan(Plan plan)
		{
			if(plan.LoopPeriod == 0 || plan.PState != 0)
			{
				if (QueryTimeType == 0 && (plan.StartTime < MinTime || plan.StartTime > MaxTime)) return false;
				else if (QueryTimeType == 1 && (plan.EndTime < MinTime || plan.EndTime > MaxTime)) return false;
			}
			else if (QueryTimeType != -1)
			{
				if (MaxTime < MinTime) return false;
				TimeSpan minSpan = MinTime - (QueryTimeType == 0 ? plan.StartTime : plan.EndTime);
				TimeSpan maxSpan = MaxTime - (QueryTimeType == 0 ? plan.StartTime : plan.EndTime);

				if (maxSpan.Ticks < 0) return false;
				
				if (PosMod(maxSpan.Ticks, new TimeSpan(1, 0, 0, 0).Ticks * plan.LoopPeriod) >= PosMod(minSpan.Ticks - 1, new TimeSpan(1, 0, 0, 0).Ticks * plan.LoopPeriod))
					if ((maxSpan - minSpan).Ticks < new TimeSpan(1, 0, 0, 0).Ticks * plan.LoopPeriod)
						return false;
			}
			if (PState != -1 && (plan.PState == 0) != (PState == 0)) return false;
			if (RegexString != "")
			{
				Regex regex = new Regex(RegexString);
				Match planNameMatch = regex.Match(plan.Name);
				if (!planNameMatch.Success) return false;
			}
			return true;
		}
	}

	public class PlanManager
	{
		/*
         * void DeletePlan  删除计划
         * void FinishPlan  完成计划
         * List QueryPlan   查询计划
         * Plan GetPlanByID 按id查询计划
         * List GetRecentPlans  获取近期计划
         * int GetPlanIndex 获取计划在数组中的索引
         */

		static public int nextID;
		static public List<Plan> plans;
		static public bool inited = false;
		static public Notifier notifier = new Notifier();

        static public event RefreshData StartRefresh;

		public static int GetNextID()
		{
			int oid = nextID++;
			FileManager.PlanNextID = nextID;
			FileManager.Write();
			return oid;
		}

		public static void Initialrize(string userName)
		{
			PlanDBManager dbManager = new PlanDBManager();
			//初次初始化时 读取nextID
			if (!inited)
			{
				FileManager.Read();
				nextID = FileManager.PlanNextID;
				inited = true;

				//如果遇到文件损坏的情况 则进行恢复处理
				//处理耗时可能较长 所以一般情况下仍从文件读取
				if (nextID == 1)
				{
					List<Plan> allPlans = dbManager.GetAllPlan();
					if (allPlans.Count != 0)
						nextID = dbManager.GetAllPlan().Max(p => p.PlanID) + 1;
				}
			}
			plans = dbManager.GetUserPlan(userName);
		}

		public static void AddPlan(Plan plan)
		{
			PlanDBManager dbManager = new PlanDBManager();
			plan.PlanID = GetNextID();
			dbManager.addPlan(plan);
			notifier.AddPlan(plan);
			plans.Add(plan);
		}

		public static void DeletePlan(Plan plan)
		{
			PlanDBManager dbManager = new PlanDBManager();
			int planID = plan.PlanID;
			int index = GetPlanIndex(planID);
			if (index != -1)
			{
				dbManager.deletePlan(planID);
				notifier.ManualFinishPlan(planID);
				plans.RemoveAt(index);
			}
		}

		public static void DeletePlan(int planID)
		{
			PlanDBManager dbManager = new PlanDBManager();
			int index = GetPlanIndex(planID);
			if (index != -1)
			{
				dbManager.deletePlan(planID);
				notifier.ManualFinishPlan(planID);
				plans.RemoveAt(index);
			}
		}

		public static void ModifyPlan(Plan modifiedPlan)
		{
			int index = GetPlanIndex(modifiedPlan.PlanID);
			if (index != -1)
			{
				notifier.UpdatePlan(modifiedPlan);
				plans[index] = modifiedPlan;
				PlanDBManager dbManager = new PlanDBManager();
				dbManager.modifyPlan(modifiedPlan);
			}
		}

		public static void FinishPlan(int planID, string comment, int score)
		{
			int index = GetPlanIndex(planID);
			if (index != -1)
			{
				PlanDBManager dbManager = new PlanDBManager();
				plans[index].Comment = comment;
				plans[index].Score = score;
				plans[index].PState = 1;
				dbManager.modifyPlan(plans[index]);
				notifier.ManualFinishPlan(planID);
				UserDBManager userDBManager = new UserDBManager();
				User user = userDBManager.GetUser(plans[index].UserName);
				user.Score += score;
				userDBManager.modifyUser(user);
				if (score != 0)
				{
					Turnover turnover = new Turnover();
					turnover.Reason = "完成" + plans[index].Name + "任务奖励";
					turnover.ScoreChange = score;
					turnover.Time = DateTime.Now;
					turnover.UserName = user.UserName;
					TurnoverManager.AddTurnover(turnover);
				}
				if(plans[index].LoopPeriod != 0)
					AddPlan(plans[index].NextLoop());
			}
		}

		public static List<Plan> QueryPlan(PlanQueryArgs arg)
		{
			return new List<Plan>(from plan in plans where arg.JudgePlan(plan) select plan);
		}

		public static Plan GetPlanClone(int planID)
		{
			int index = GetPlanIndex(planID);
			if (index != -1) return new Plan(plans[index]);
			else return null;
		}

		public static int GetPlanIndex(int planID)
		{
			for (int i = 0; i < plans.Count; i++)
			{
				if (plans[i]!=null && plans[i].PlanID == planID)
					return i;
			}
			return -1;
		}

		public static void AutoFinish(List<int> removeID)
		{
			PlanDBManager dbManager = new PlanDBManager();
			foreach (int id in removeID)
			{
				int index = GetPlanIndex(id);
				if (index != -1)
				{
					plans[index].Comment = "任务已过期";
					plans[index].Score = 0;
                    plans[index].PState = 2;
					dbManager.modifyPlan(plans[index]);
					if (plans[index].LoopPeriod != 0) AddPlan(plans[index].NextLoop());
					StartRefresh?.Invoke();
				}
			}
		}
	}
}